﻿using System;
using System.Collections.Generic;
using System.Linq;
using SapaFinance.Domain.Extensions;

namespace SapaFinance.Domain.Model
{
    public class Order : AbstractEntity
    {
        protected Order() { }

        public Order(User user, decimal payment, Currency currency)
            : this()
        {
            CreatedBy = new Identity(user);
            Change(user);
            PartialPayment = new HashSet<Share>();
            Payment = Money.Create(payment, currency);
            //  CreatePartialPayment(requests);
        }

        public bool HasPayment
        {
            get { return Payment != null; }
        }

        //public bool MayToBeAdded(Request request)
        //{
        //    if (HasPayment){
        //        var paidAmount = GetPaidAmount(request.Payment.Currency);
        //        return Payment >=  (paidAmount + request.Payment);
        //    }
        //    return false;
        //}
        //private void CreatePartialPayment(IEnumerable<Request> requests)
        //{
        //    //сортируем список. сначала маленькие платежи, потом большие
        //    var sortedList = requests.OrderBy(x => x.Payment.Amount);
        //    foreach (var request in sortedList)
        //    {
        //        var outstandingAmount = request.GetOutstandingAmount();
        //        var notPaidAmount = GetNotPaidAmount();
        //        //если недоплата в заявке больше, чем недоплата в распоряжении, то добавляем в распоряжение заявку с остатком из распоряжения, в противном случае остаток из заявки
        //        var share = outstandingAmount > notPaidAmount ? new Share(request, this, notPaidAmount) : new Share(request, this, outstandingAmount);
        //        request.AddPartialPayment(share);
        //        PartialPayment.Add(share);
        //    }
        //}

        public void AddRequest(Request request)
        {
            if (this.HasPayment)
            {
                var outstandingAmount = request.GetNotPaidAmount();
                var notPaidAmount = GetNotPaidAmount();
                //если есть еще остаток в распоряжении, который можно включить в оплату заявки
                if (notPaidAmount.Amount > 0){
                    //если недоплата в заявке больше, чем недоплата в распоряжении, то добавляем в распоряжение заявку с остатком из распоряжения, в противном случае остаток из заявки
                    var share = outstandingAmount > notPaidAmount ? new Share(request, this, notPaidAmount) : new Share(request, this, outstandingAmount);
                    request.AddPartialPayment(share);
                    PartialPayment.Add(share);
                }
            }
        }
        public virtual ICollection<Share> PartialPayment { get; private set; }
        public virtual Identity CreatedBy { get; private set; }
        public virtual Identity ChangedBy { get; private set; }
        public virtual Identity ExecutedBy { get; private set; }
        public virtual DateTime PaymentPeriod { get; set; }
        public virtual Money Payment { get; private set; }
        public virtual string PaymentPurpose { get; set; }
        public virtual Agent Agent { get; private set; }
        public virtual int Unique { get; private set; }

        public void Change(User user)
        {
            ChangedBy = new Identity(user);
        }

        public void Execute(User user)
        {
            ExecutedBy = new Identity(user);
        }

        public void SetAgent(Agent agent)
        {
            Agent = agent;
        }

        public void SetPayment(decimal payment, Currency currency)
        {
            Payment = Money.Create(payment, currency);
        }

        public Corporation GetPayeeSharePie()
        {
            return PartialPayment.First().Request.Payee;
        }

        public Corporation GetPayerSharePie()
        {
            return PartialPayment.First().Request.Payer;
        }

        /// <summary>
        /// остаток в распоряжении по оплате заявок
        /// </summary>
        /// <returns></returns>
        public Money GetNotPaidAmount()
        {
            return PartialPayment.Any() ? Payment - GetPaidAmount(Payment.Currency) : Payment;
        }

        /// <summary>
        /// сумма по входящим в распоряжение заявкам
        /// </summary>
        /// <returns></returns>
        public Money GetPaidAmount(Currency currency)
        {
            if (PartialPayment.Any())
                return PartialPayment.Sum(x => x.Amount);
            return Money.Create(0, currency);
        }
    }
}